﻿using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Framework;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;

namespace Project
{
    public interface IBuffOwner
    {
        void Execute(BuffID buffID, float value);
        float GetPassiveValue(BuffID buffID);
        float GetSouceData(BuffID buffID);
        string AddIconEventName { get; }
    }
    public class BuffSystem : ISingeleton
    {
        public static BuffSystem Global => Singleton<BuffSystem>.Instance;

        private Dictionary<BuffID, BuffConfig> mConfigs;
        // 每个buff 拥有者都会被挂上一组buff
        private Dictionary<IBuffOwner, List<Buff>> mBuffs;

        void ISingeleton.Init()
        {
            mConfigs = new Dictionary<BuffID, BuffConfig>();
            mBuffs = new Dictionary<IBuffOwner, List<Buff>>();

            foreach (var data in Resources.Load<SO_BuffConfig>("SO/BuffConfig"))
            {
                // 如果配置已经存在 说明配置表存在重复数据
                if (mConfigs.ContainsKey(data.ID))
                {
                    Debug.Log($"配置表存在重复数据{data.ID}");
                }
                else
                {
                    mConfigs.Add(data.ID, data);
                }
            }
        }
        /// <summary>
        /// 给某个对象添加Buff
        /// </summary>
        public void AddBuff(IBuffOwner owner, BuffID buffID)
        {
            // 如果buff对象不存在 创建一个buff列表先
            if (!mBuffs.TryGetValue(owner, out var list))
            {
                list = new List<Buff>();
                mBuffs.Add(owner, list);
            }
            // 如果里面的buff数据 为空 说明当前没有持有buff
            if (list.Count == 0)
            {
                CreateBuff(buffID, owner, list);
                return;
            }
            // 如果里面有存在buff 查找是否有相同的buff
            var buff = list.Find(info => info.ID == buffID);
            // 如果没有就添加buff
            if (buff == null) CreateBuff(buffID, owner, list);
            // 如果返回了对象 
            else if (Get(buffID, out var config))
            {
                // 如果可以叠加Buff层数 就叠加
                if (config.IsStackable) buff.AddHierarchy();
                // 重置buff计时器
                buff.Set(config.Duration);
            }
        }
        // 创建对应buff给某个对象
        private void CreateBuff(BuffID buffID, IBuffOwner owner, List<Buff> list)
        {
            // 直接添加buff 对基本数据进行查表
            if (Get(buffID, out var config))
            {
                Debug.Log($"{buffID}被添加");
                var info = new Buff(buffID);
                // 如果是计时buff 注册一个计时任务 用于到达时间移除
                if (config.IsTimeBuff)
                {
                    StartTiming(config, owner, info);
                }
                list.Add(info);
                // 如果事件不为空
                if (string.IsNullOrEmpty(owner.AddIconEventName)) return;
                // 生成 buff 图标
                var ui = GameObject.Instantiate(Resources.Load<GameObject>("Prefab/BuffItem"));
                var icon = ui.GetComponent<Image>();
                // 缓存 Icon
                info.Icon = icon;
                // 添加 图片
                icon.sprite = config.sprite;
                // 给UI窗口发送添加Buff的事件
                EventCenter.GetInstance().EventTrigger(owner.AddIconEventName, ui);
            }
        }
        public void RemoveBuff(IBuffOwner owner, BuffID buffID)
        {
            // 移除buff必须存在才能移除
            if (mBuffs.TryGetValue(owner, out var list))
            {
                // 如果buff数量为0 就不执行移除
                if (list.Count == 0) return;
                // 查找该ID是否存在
                int index = list.FindIndex(info => info.ID == buffID);
                // 如果索引大于等于0 说明存在 即可以删除
                if (index >= 0)
                {
                    // 移除UI
                    list[index].Destroy();
                    // 删除元素
                    list.RemoveAt(index);
                }
                Debug.Log($"{buffID}被移除");
            }
        }
        // 开启计时
        private async void StartTiming(BuffConfig config, IBuffOwner owner, Buff buff)
        {
            buff.Set(config.Duration);

            if (config.IsPassive)
            {
                while (buff.IsContinue)
                {
                    buff.Update();
                    await Task.Yield();
                }
            }
            else
            {
                float timer = config.TriggerInterval;
                // 计算数值或倍率的增量 
                float delta = owner.GetPassiveValue(buff.ID) * buff.StackedLayer;
                // 
                while (buff.IsContinue)
                {
                    timer += Time.deltaTime;
                    if (timer > config.TriggerInterval)
                    {
                        float souce = owner.GetSouceData(buff.ID);
                        switch (config.Op)
                        {
                            case E_Operator.Add: souce += delta; break;
                            case E_Operator.Sub: souce -= delta; break;
                            case E_Operator.Mul: souce *= (1 + delta); break;
                            case E_Operator.Div: souce /= (1 - delta); break;
                        }
                        owner.Execute(config.ID, souce);
                        timer = 0;
                    };
                    buff.Update();
                    await Task.Yield();
                }
            }
            // 移除buff
            RemoveBuff(owner, config.ID);
        }
        /// <summary>
        /// 某个对象是否包含某个BUFF
        /// </summary>
        public bool Contains(IBuffOwner owner, BuffID buffID)
        {
            if (mBuffs.TryGetValue(owner, out var list))
            {
                if (list.Count > 0)
                {
                    return list.FindIndex(info => info.ID == buffID) >= 0;
                }
            }
            return false;
        }
        /// <summary>
        /// 计算当前所有被动技能
        /// </summary>
        public double CalcAllPassiveBuff(IBuffOwner owner, double value)
        {
            if (mBuffs.TryGetValue(owner, out var list))
            {
                if (list.Count == 0) return value;
                // 用于存储加法的栈
                var stack = new Stack<(float, E_Operator)>();

                foreach (var buff in list)
                {
                    // 获取buff配置 如果是被动 就参与计算
                    if (Get(buff.ID, out var config) && config.IsPassive)
                    {
                        float delta = owner.GetPassiveValue(buff.ID) * buff.StackedLayer;

                        switch (config.Op)
                        {
                            case E_Operator.Add:
                            case E_Operator.Sub:
                                stack.Push((delta, config.Op));
                                continue;
                            case E_Operator.Mul: value *= (1 + delta); break;
                            case E_Operator.Div: value /= (1 - delta); break;
                        }
                    }
                }
                while (stack.Count > 0)
                {
                    var info = stack.Pop();
                    switch (info.Item2)
                    {
                        case E_Operator.Add: value += info.Item1; break;
                        case E_Operator.Sub: value -= info.Item1; break;
                    }
                }
            }
            return value;
        }
        /// <summary>
        /// 获取buff配置表
        /// </summary>
        public bool Get(BuffID buffID, out BuffConfig data)
        {
            if (mConfigs.TryGetValue(buffID, out data)) return true;
            throw new Exception($"{buffID}未被配置");
        }
        /// <summary>
        /// 清空某个对象的buff
        /// </summary>
        public void Clear(IBuffOwner owner)
        {
            if (mBuffs.TryGetValue(owner, out var list))
            {
                for (int i = 0; i < list.Count; i++)
                {
                    list[i].Destroy();
                }
                list.Clear();
            }
        }
        /// <summary>
        /// 清空所有对象的buff
        /// </summary>
        public void ClearAll()
        {
            foreach (var list in mBuffs.Values)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    list[i].Destroy();
                }
                list.Clear();
            }
            mBuffs.Clear();
        }
    }
}